Selective Color
Volume Number: 10
Issue Number: 1
Column Tag: C Workshop
Using custom color buttons on color and black and white Macs
By Mark W. Batten, Washington, D.C.
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
Custom color buttons enliven any application, but if the programmer is writing
software that must run on both black-and-white and color machines (as most of us
are), it may seem daunting to write code that will draw the button different ways on
differently configured machines. This article demonstrates a simple scheme to create
buttons that are smart enough to be custom-drawn on color machines, and as regular
Toolbox buttons on black-and-white machines.
The key to the technique is the Toolbox routine SetDItem. Although generally used
only to change a dialog item’s rectangle, SetDItem is actually quite powerful; it lets
you change just about everything associated with a dialog item. In this example, we’ll
use it to point the Mac to our own CDEF to draw the button on color machines.
Setting Up The Resources
First, you need to create the CDEF that draws the color button. At the end of this
article is source code for a sample button with a nice 3-D appearance.
(This particular CDEF uses an “auxiliary control record” (as described in Inside
Macintosh, Vol. 5, pp. 216-18) to tell it what colors to draw the control in. If you’ve
never encountered these arcane things, don’t worry; you don’t need to understand them
to implement the scheme described in the article).
Second, create a dialog (DLOG) and a dialog item list (DITL) for your application
as you normally would. Be sure that your DLOG will not be displayed when it’s loaded
(in ResEdit, be sure the “Initially visible” box is unchecked). The DITL should use
normal, vanilla buttons for OK and Cancel. That way, the resource is all set up to run
normally on black-and-white machine, without any more work.
For this example, you also need to create two other resources: a dialog color table
(‘dctb’) and a control color table (‘cctb’). (The correct values for the sample are
listed at the end of this article). The ‘dctb’ serves two functions here: first, when you
call GetNewDialog to read in a dialog, the Mac will automatically make it a color dialog,
based on a CGrafPort, if the Mac finds a ‘dctb’ with the same ID as the DLOG resource.
Second, the ‘dctb’ colors the content area of the dialog, which makes our button look
better. The CDEF uses the ‘cctb’ resource to determine what colors to use when
drawing the custom button.
Making The Switch
On a black-and-white Mac, the dialog will perform as it’s supposed to, without
any special code in your application. To do something fancier on color machines, your
application just has to alert the Dialog Manager to use our custom CDEF instead of the
standard one. Here are the necessary steps.
1. In your application’s initialization routines, load the CDEF resource and the cctb
color table into variables, like this:
/* 1 */
Handle myCDEF; /* handle to our custom CDEF */
CTabHandle CtrlCTab; /* handle to colors for our control */
myCDEF=GetResource('CDEF',32);
CtrlCTab=(CTabHandle)GetResource('cctb',128);
2. When you’re ready to create the dialog, load it with GetNewDialog (or build it
from scratch with NewDialog). Then call the following routine, which uses
SetDItem to tell the Mac where to find our custom code. Pass the DialogPtr in d
and the item number of the button you want to convert in i:
/* 2 */
ConvertToColorButtons(d,i)
DialogPtr d;
int i;
{
int j;
Handle tItem;
Rect box;
char n[31];
GetDItem(d,i,&j,&tItem,&box);
if(j==ctrlItem+btnCtrl ||
j==ctrlItem+btnCtrl+itemDisable){
SetCtlColor(tItem,CtrlCTab);
(**((ControlHandle)tItem)).contrlDefProc=myCDEF;
j&=127;
SetDItem(d,i,j,tItem,&box);
}
}
Here's the CDEF code.
pascal long main(var,CH,msg,par)
int msg,var;
ControlHandle CH;
long par;
{
long l;
l=0L;
switch(msg){
case 0:
doDraw(CH);
break;
case 1:
l=(long)doTest(par,CH);
break;
case 2:
doCalc(par,CH);
break;
}
return l;
}
doTest(par,CH)
long par;
ControlHandle CH;
{
Point pt;
pt.v=HiWord(par);
pt.h=LoWord(par);
return (int)PtInRect(pt,&((**CH).contrlRect));
}
doCalc(par,CH)
RgnHandle par;
ControlHandle CH;
{
par=(RgnHandle)((long)par&0x7FFFFFFF);
RectRgn(par,&((**CH).contrlRect));
}
doDraw(CH)
ControlHandle CH;
{
int j,k,*p;
Handle tItem;
Rect r;
RGBColor rgb,rgb1,rgb2;
AuxCtlHandle ax;
FontInfo inf;
r=(**CH).contrlRect;
j=StringWidth((**CH).contrlTitle);
GetFontInfo(&inf);
k=inf.ascent+inf.descent;
k=(r.top+r.bottom+k)/2;
MoveTo((r.left+r.right-j)/2,k-inf.descent);
DrawString((**CH).contrlTitle);
GetAuxCtl(CH,&ax);
p=(int *)&(**(**ax).acCTable).ctTable[0].rgb.red;
rgb.red=p[0]; /* 21845, 0x5555*/
rgb.green=p[1]; /* 21845, 0x5555*/
rgb.blue=p[2]; /* 21845, 0x5555*/
rgb1.red=p[4]; /* 34952, 0x8888*/
rgb1.green=p[5]; /* 34952, 0x8888*/
rgb1.blue=p[6]; /* 34952, 0x8888*/
rgb2.red=rgb2.green=rgb2.blue=0xFFFF;
PenSize(2,2);
RGBForeColor(&rgb);
MoveTo(r.right-2,r.top);
LineTo(r.left,r.top);
LineTo(r.left,r.bottom-2);
RGBForeColor(&rgb2);
MoveTo(r.right-2,r.top+1);
LineTo(r.right-2,r.bottom-2);
LineTo(r.left,r.bottom-2);
rgb2.red=rgb2.green=rgb2.blue=0;
RGBForeColor(&rgb2);
InsetRect(&r,2,2);
FrameRect(&r);
InsetRect(&r,2,2);
if(!(**CH).contrlHilite){
PenSize(1,1);
RGBForeColor(&rgb);
MoveTo(r.left,r.top);
LineTo(r.left,r.bottom-2);
PenSize(2,2);
LineTo(r.right-2,r.bottom-2);
Move(0,-1);
PenSize(1,1);
RGBForeColor(&rgb1);
LineTo(r.left+1,r.bottom-3);
LineTo(r.left+1,r.top);
LineTo(r.right-1,r.top);
Move(0,1);
rgb2.red=rgb2.green=rgb2.blue=0xFFFF;
RGBForeColor(&rgb2);
LineTo(r.left+2,r.top+1);
}
else {
MoveTo(r.right-2,r.top);
RGBForeColor(&rgb);
LineTo(r.left,r.top);
PenSize(1,1);
LineTo(r.left,r.bottom-3);
PenSize(3,3);
LineTo(r.right-3,r.bottom-3);
PenSize(1,1);
Move(2,-1);
RGBForeColor(&rgb1);
LineTo(r.left+1,r.bottom-4);
LineTo(r.left+1,r.top+2);
LineTo(r.right-1,r.top+2);
}
rgb2.red=rgb2.green=rgb2.blue=0;
RGBForeColor(&rgb2);
}
The values for the color table resources for the example are as follows:
The control color table (type 'cctb') has two entries. The part codes are just 0
and 1 (the CDEF doesn't really use these) and the colors are {
0x5555,0x5555,0x5555 } and { 0x8888,0x8888,0x8888 }.
The dialog color table (type 'dctb') must have five entries, with part codes of
0-4, and colors as follows: { 0xAAAA,0xAAAA,0xAAAA }, { 0x5555,0x5555,
0x5555 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }.